package com.qiwenshare.file.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiwenshare.common.exception.QiwenException;
import com.qiwenshare.common.operation.FileOperation;
import com.qiwenshare.common.util.DateUtil;
import com.qiwenshare.common.util.security.SessionUtil;
import com.qiwenshare.file.api.IFileService;
import com.qiwenshare.file.api.RoleFilePermissionService;
import com.qiwenshare.file.component.AsyncTaskComp;
import com.qiwenshare.file.component.FileDealComp;
import com.qiwenshare.file.domain.*;
import com.qiwenshare.file.domain.user.UserBean;
import com.qiwenshare.file.mapper.FileMapper;
import com.qiwenshare.file.mapper.ImageMapper;
import com.qiwenshare.file.mapper.MusicMapper;
import com.qiwenshare.file.mapper.UserFileMapper;
import com.qiwenshare.file.util.QiwenFileUtil;
import com.qiwenshare.file.util.SpringBeanUtil;
import com.qiwenshare.file.vo.file.FileDetailVO;
import com.qiwenshare.file.vo.file.FileListTreeVO;
import com.qiwenshare.file.vo.file.FileListVO;
import com.qiwenshare.file.vo.menu.MenuVo;
import com.qiwenshare.file.vo.role.RoleFilePermissionVo;
import com.qiwenshare.ufop.factory.UFOPFactory;
import com.qiwenshare.ufop.operation.download.Downloader;
import com.qiwenshare.ufop.operation.download.domain.DownloadFile;
import com.qiwenshare.ufop.util.UFOPUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class FileService extends ServiceImpl<FileMapper, FileBean> implements IFileService {
    public static Executor executor = Executors.newFixedThreadPool(20);
    @Resource
    FileMapper fileMapper;
    @Resource
    UserFileMapper userFileMapper;
    @Resource
    UFOPFactory ufopFactory;

    @Value("${ufop.storage-type}")
    private Integer storageType;

    @Resource
    AsyncTaskComp asyncTaskComp;
    @Resource
    MusicMapper musicMapper;
    @Resource
    ImageMapper imageMapper;
    @Resource
    FileDealComp fileDealComp;

    @Resource
    private RoleFilePermissionService roleFilePermissionService;

    @Override
    public Long getFilePointCount(String fileId) {
        LambdaQueryWrapper<UserFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserFile::getFileId, fileId);
        long count = userFileMapper.selectCount(lambdaQueryWrapper);
        return count;
    }

    @Override
    public void unzipFile(String userFileId, int unzipMode, String filePath) {
        UserFile userFile = userFileMapper.selectById(userFileId);
        FileBean fileBean = fileMapper.selectById(userFile.getFileId());
        File destFile = new File(UFOPUtils.getStaticPath() + "temp" + File.separator + fileBean.getFileUrl());


        Downloader downloader = ufopFactory.getDownloader(fileBean.getStorageType());
        DownloadFile downloadFile = new DownloadFile();
        downloadFile.setFileUrl(fileBean.getFileUrl());
        InputStream inputStream = downloader.getInputStream(downloadFile);

        try {
            FileUtils.copyInputStreamToFile(inputStream, destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }


        String extendName = userFile.getExtendName();

        String unzipUrl = UFOPUtils.getTempFile(fileBean.getFileUrl()).getAbsolutePath().replace("." + extendName, "");

        List<String> fileEntryNameList = new ArrayList<>();

        try {
            fileEntryNameList = FileOperation.unzip(destFile, unzipUrl);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("解压失败" + e);
            throw new QiwenException(500001, "解压异常：" + e.getMessage());
        }

        if (destFile.exists()) {
            destFile.delete();
        }

        if (!fileEntryNameList.isEmpty() && unzipMode == 1) {
            UserFile qiwenDir = QiwenFileUtil.getQiwenDir(userFile.getUserId(), userFile.getFilePath(), userFile.getFileName());
            userFileMapper.insert(qiwenDir);
        }
        for (int i = 0; i < fileEntryNameList.size(); i++) {
            String entryName = fileEntryNameList.get(i);
            asyncTaskComp.saveUnzipFile(userFile, fileBean, unzipMode, entryName, filePath);

        }
    }

    @Override
    public void updateFileDetail(String userFileId, String identifier, long fileSize) {
        UserFile userFile = userFileMapper.selectById(userFileId);
        String currentTime = DateUtil.getCurrentTime();
        FileBean fileBean = new FileBean();
        fileBean.setIdentifier(identifier);
        fileBean.setFileSize(fileSize);
        fileBean.setModifyTime(currentTime);
        fileBean.setModifyUserId(SessionUtil.getUserId());
        fileBean.setFileId(userFile.getFileId());
        fileMapper.updateById(fileBean);
        userFile.setUploadTime(currentTime);
        userFile.setModifyTime(currentTime);
        userFile.setModifyUserId(SessionUtil.getUserId());
        userFileMapper.updateById(userFile);
    }

    @Override
    public FileDetailVO getFileDetail(String userFileId) {
        UserFile userFile = userFileMapper.selectById(userFileId);
        FileBean fileBean = fileMapper.selectById(userFile.getFileId());
        Music music = musicMapper.selectOne(new QueryWrapper<Music>().eq("fileId", userFile.getFileId()));
        Image image = imageMapper.selectOne(new QueryWrapper<Image>().eq("fileId", userFile.getFileId()));

        if ("mp3".equalsIgnoreCase(userFile.getExtendName()) || "flac".equalsIgnoreCase(userFile.getExtendName())) {
            if (music == null) {
                fileDealComp.parseMusicFile(userFile.getExtendName(), fileBean.getStorageType(), fileBean.getFileUrl(), fileBean.getFileId());
                music = musicMapper.selectOne(new QueryWrapper<Music>().eq("fileId", userFile.getFileId()));
            }
        }

        FileDetailVO fileDetailVO = new FileDetailVO();
        BeanUtil.copyProperties(userFile, fileDetailVO);
        BeanUtil.copyProperties(fileBean, fileDetailVO);
        fileDetailVO.setMusic(music);
        fileDetailVO.setImage(image);
        return fileDetailVO;
    }

    @Override
    public List<FileListTreeVO> queryDicTree() {
        LambdaQueryWrapper<UserFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByDesc(UserFile::getIsDir, UserFile::getUploadTime);
        //lambdaQueryWrapper.eq(UserFile::getIsDir, 1);
        lambdaQueryWrapper.eq(UserFile::getDeleteFlag, 0);
        lambdaQueryWrapper.eq(UserFile::getFileMode, 1);

        List<UserFile> list = userFileMapper.selectList(lambdaQueryWrapper);
        List<FileListTreeVO> treeList = new ArrayList<>();

        for (UserFile file : list) {
            if ("/".equals(file.getFilePath())) {
                FileListTreeVO treeVo = SpringBeanUtil.copyProperties(file, FileListTreeVO.class);
                treeVo.setKey(file.getUserFileId());
                treeVo.setTitle(file.getIsDir() == 0 ? file.getFileName() + "." + file.getExtendName() : file.getFileName());
                treeVo.setLeaf(file.getIsDir() == 0);
                treeVo.setTopUserFileId(file.getUserFileId());
                treeList.add(treeVo);
            }
        }
        generateTree(list, treeList);
        return treeList;
    }

    @Override
    public List<FileListTreeVO> queryPortalDicTree() {
        List<FileListTreeVO> totalDicTree = this.queryDicTree();
        List<FileListTreeVO> userDicTree = new ArrayList<>();
        List<RoleFilePermissionVo> roleFilePermissionVoList = roleFilePermissionService.queryListByUser();
        for (FileListTreeVO fileListTreeVO: totalDicTree) {
            for (RoleFilePermissionVo filePermissionVo: roleFilePermissionVoList) {
                if (fileListTreeVO.getUserFileId().equals(filePermissionVo.getUserFileId())) {
                    if (!(filePermissionVo.getUpload() == 2 && filePermissionVo.getDownload() == 2 && filePermissionVo.getDel() == 2 && filePermissionVo.getModify() == 2)) {
                        userDicTree.add(fileListTreeVO);
                    }
                    break;
                }
            }
        }
        return userDicTree;
    }

    private void generateTree(List<UserFile> fileList, List<FileListTreeVO> treeList) {
        for (FileListTreeVO treeVo : treeList) {
            if (treeVo.getIsDir() == 1) {
                List<FileListTreeVO> children = new ArrayList<>();
                for (UserFile file : fileList) {
                    if (file.getFilePath().equals(treeVo.getFilePath() + ("/".equals(treeVo.getFilePath()) ? "" : "/") + treeVo.getFileName())) {
                        FileListTreeVO dVo = SpringBeanUtil.copyProperties(file, FileListTreeVO.class);
                        dVo.setKey(file.getUserFileId());
                        dVo.setTitle(file.getIsDir() == 0 ? file.getFileName() + "." + file.getExtendName() : file.getFileName());
                        dVo.setLeaf(file.getIsDir() == 0);
                        dVo.setTopUserFileId(treeVo.getTopUserFileId());
                        children.add(dVo);
                    }
                }
                treeVo.setChildren(children);
                if (CollectionUtil.isNotEmpty(children)) {
                    generateTree(fileList, treeVo.getChildren());
                }
            }
        }
    }

    private String getLastDirName(String filePath) {
        String[] pathArr = filePath.split("/");
        return pathArr.length > 1 ? pathArr[pathArr.length - 1] : "";
    }
}
